package drds.common.db.sql_mapping.dynamic_tag.xml_node;

import drds.common.$;
import lombok.Getter;
import lombok.Setter;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


public class XmlNode {
    @Setter
    @Getter
    private final XmlNodeParser xmlNodeParser;
    @Setter
    @Getter
    private final org.w3c.dom.Node node;
    @Setter
    @Getter
    private final String name;
    @Setter
    @Getter
    private final Properties attributes;

    @Setter
    @Getter
    private final String body;
    //
    @Setter
    @Getter
    private final Properties variables;

    public XmlNode(XmlNodeParser xmlNodeParser, org.w3c.dom.Node node, Properties variables) {
        this.xmlNodeParser = xmlNodeParser;
        this.node = node;
        this.name = node.getNodeName();
        this.attributes = parseAttributes(node);
        this.body = parseBody(node);
        this.variables = variables;
    }


    //
    public XmlNode getParentXmlNode() {
        org.w3c.dom.Node parentNode = node.getParentNode();
        if (!(parentNode instanceof Element)) {
            return null;
        } else {

            return new XmlNode(xmlNodeParser, parentNode, variables);
        }
    }

    public XmlNode newXmlNode(org.w3c.dom.Node node) {
        return new XmlNode(xmlNodeParser, node, variables);
    }

    //
    public String getValueBasedIdentifier() {
        StringBuilder sb = new StringBuilder();
        XmlNode current = this;
        while (current != null) {
            if (current != this) {
                sb.insert(0, "_");
            }
            String value = current.getStringAttribute("id",
                    current.getStringAttribute("key",
                            current.getStringAttribute("property", null)));
            if (value != null) {
                value = value.replace('.', '_');
                sb.insert(0, "]");
                sb.insert(0,
                        value);
                sb.insert(0, "[");
            }
            sb.insert(0, current.getName());
            current = current.getParentXmlNode();
        }
        return sb.toString();
    }

    //
    public List<XmlNode> evaluateXmlNodeList(String expression) {
        return xmlNodeParser.evaluateXmlNodeList(node, expression);
    }

    public XmlNode evaluateNode(String expression) {
        return xmlNodeParser.evaluateNode(node, expression);
    }

    //
    public String evaluateString(String expression) {

        return xmlNodeParser.evaluateString(node, expression);
    }

    public Boolean evaluateBoolean(String expression) {
        return xmlNodeParser.evaluateBoolean(node, expression);
    }

    public Float evaluateFloat(String expression) {
        return xmlNodeParser.evaluateFloat(node, expression);
    }

    public Double evaluateDouble(String expression) {
        return xmlNodeParser.evaluateDouble(node, expression);
    }

    //
    public String getStringBody() {
        return getStringBody(null);
    }

    public String getStringBody(String defaultValue) {
        if (body == null) {
            return defaultValue;
        } else {
            return body;
        }
    }

    public Boolean getBooleanBody() {
        return getBooleanBody(null);
    }

    public Boolean getBooleanBody(Boolean defaultValue) {
        if (body == null) {
            return defaultValue;
        } else {
            return Boolean.valueOf(body);
        }
    }

    public Integer getIntBody() {
        return getIntBody(null);
    }

    public Integer getIntBody(Integer defaultValue) {
        if (body == null) {
            return defaultValue;
        } else {
            return Integer.parseInt(body);
        }
    }

    public Long getLongBody() {
        return getLongBody(null);
    }

    public Long getLongBody(Long defaultValue) {
        if (body == null) {
            return defaultValue;
        } else {
            return Long.parseLong(body);
        }
    }

    //
    private Properties parseAttributes(org.w3c.dom.Node node) {
        Properties attributes = new Properties();
        NamedNodeMap attributeNodes = node.getAttributes();
        if (attributeNodes != null) {
            for (int i = 0; i < attributeNodes.getLength(); i++) {
                org.w3c.dom.Node attribute = attributeNodes.item(i);
                String value = GlobalVariableReplacementParser.parse(attribute.getNodeValue(), variables);
                attributes.put(attribute.getNodeName(), value);
            }
        }
        return attributes;
    }

    public String getStringAttribute(String name) {
        return getStringAttribute(name, null);
    }

    public String getStringAttribute(String name, String defaultValue) {
        String value = attributes.getProperty(name);
        if (value == null) {
            return defaultValue;
        } else {
            return value;
        }
    }

    public Boolean getBooleanAttribute(String name) {
        return getBooleanAttribute(name, null);
    }

    public Boolean getBooleanAttribute(String name, Boolean defaultValue) {
        String value = attributes.getProperty(name);
        if (value == null) {
            return defaultValue;
        } else {
            return Boolean.valueOf(value);
        }
    }

    public Integer getIntAttribute(String name) {
        return getIntAttribute(name, null);
    }

    public Integer getIntAttribute(String name, Integer defaultValue) {
        String value = attributes.getProperty(name);
        if (value == null) {
            return defaultValue;
        } else {
            return Integer.parseInt(value);
        }
    }

    public Long getLongAttribute(String name) {
        return getLongAttribute(name, null);
    }

    public Long getLongAttribute(String name, Long defaultValue) {
        String value = attributes.getProperty(name);
        if (value == null) {
            return defaultValue;
        } else {
            return Long.parseLong(value);
        }
    }

    public Float getFloatAttribute(String name) {
        return getFloatAttribute(name, null);
    }

    public Float getFloatAttribute(String name, Float defaultValue) {
        String value = attributes.getProperty(name);
        if (value == null) {
            return defaultValue;
        } else {
            return Float.parseFloat(value);
        }
    }

    public Double getDoubleAttribute(String name) {
        return getDoubleAttribute(name, null);
    }

    public Double getDoubleAttribute(String name, Double defaultValue) {
        String value = attributes.getProperty(name);
        if (value == null) {
            return defaultValue;
        } else {
            return Double.parseDouble(value);
        }
    }

    //
    public List<XmlNode> getChildrenXmlNodeList() {
        List<XmlNode> xmlNodeList = new ArrayList<>();
        NodeList nodeList = node.getChildNodes();
        if (nodeList != null) {
            for (int i = 0, index = nodeList.getLength(); i < index; i++) {
                org.w3c.dom.Node node = nodeList.item(i);
                if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    xmlNodeList.add(new XmlNode(xmlNodeParser, node, variables));
                }
            }
        }
        return xmlNodeList;
    }

    public Properties getChildrenXmlNodeListAsProperties() {
        Properties properties = new Properties();
        for (XmlNode xmlNode : getChildrenXmlNodeList()) {
            String name = xmlNode.getStringAttribute("name");
            String value = xmlNode.getStringAttribute("key");
            if (name != null && value != null) {
                properties.setProperty(name, value);
            }
        }
        return properties;
    }
    //


    private String parseBody(org.w3c.dom.Node node) {
        String data = getBodyData(node);
        if (data == null) {
            NodeList nodeList = node.getChildNodes();
            for (int index = 0; index < nodeList.getLength(); index++) {
                org.w3c.dom.Node childNode = nodeList.item(index);
                data = getBodyData(childNode);
                if (data != null) {
                    break;
                }
            }
        }
        return data;
    }

    private String getBodyData(org.w3c.dom.Node node) {
        if (node.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE//
                ||//
                node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {//


            String data = ((CharacterData) node).getData();
            data = GlobalVariableReplacementParser.parse(data, variables);
            data = trimTnsOfBody(data);
            return data;
        }
        return null;
    }

    /**
     * 对body数据去掉\t\n\s
     */
    public String trimTnsOfBody(String string) {
        if ($.isNotNullAndNotEmpty(string)) {
            string = string.replace("\t\n", " ").replace("\t", " ").replace("\n", " ");
            string = " " + string.trim() + " ";
        }
        return string;
    }

}
